package web;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import json.JSONArray;
import json.JSONException;
import json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;


public class Retriever {

	/** The max result number*/
    private final static int MAX_RESULTS = 64;

    /** Number of results per query*/
    private final static int RESULTS_PER_QUERY = 8;

    /** Initial URL for google searches*/
    private final static String QUERY_BASE_URL = "http://ajax.googleapis.com/ajax/services/search/web?rsz=large&v=1.0";

    /** Object to make HTTP request. */
    HttpClient httpClient;
    
    /**
     *  Default constructor.
     */    
    public Retriever() {
        this.httpClient = new HttpClient();
    }

    /**
     * Retrieve the results for the given query 
     * 
     * @param query 
     * @return the result list
     * @throws IOException communication error with the site
     */
    public List<String> retrieve(String query) throws IOException {

        List<String> results = new ArrayList<String>(MAX_RESULTS);
        try {
            String encodedQuery = URLEncoder.encode(query, "UTF-8");
            JSONObject responseData = this.retrieveJSON(QUERY_BASE_URL + "&q=" + encodedQuery);
            JSONObject cursor = responseData.getJSONObject("responseData").getJSONObject("cursor");

            // if there's at least one page
            if (cursor.has("pages")) {

                // determine the number of queries to do
                int maxQueries = (int) Math.ceil((double) MAX_RESULTS / (double) RESULTS_PER_QUERY);
                int queries = cursor.getJSONArray("pages").length();

                if (queries > maxQueries) {
                    queries = maxQueries;
                }

                // actually do the queries
                for (int i = 0; i < queries; i++) {
                    int start = i * RESULTS_PER_QUERY;
                    responseData = this.retrieveJSON(QUERY_BASE_URL + "&start=" + start + "&q=" + encodedQuery);
                    JSONArray pages = responseData.getJSONObject("responseData").getJSONArray("results");

                    for (int j = 0; j < pages.length(); j++) {
                        if (results.size() < MAX_RESULTS) {
                            String url = pages.getJSONObject(j).getString("url");                          
                            results.add(url);
                        }
                    }
                }
            }

        } catch (UnsupportedEncodingException e) {
            // never gets here
        } catch (MalformedURLException e) {
            // never gets here
        } catch (JSONException e) {
            // Google returned something strange. Connection error?
            throw new IOException("Impossible parse the JASON results");
        }

        return results;
    }

    private JSONObject retrieveJSON(String url) throws IOException, JSONException {
        HttpMethod method = new GetMethod(url);
        this.httpClient.executeMethod(method);
        
        return new JSONObject(method.getResponseBodyAsString());
    }
}
